﻿using System;

namespace BSharp.Compiler
{
	public class SemanticAnalyser : AstVisitor
	{
		private BSharpContext context;
		private SymbolTable symbolTable = new SymbolTable ();

		public SemanticAnalyser (BSharpContext context)
		{
			this.context = context;
		}

		public SymbolTable Analyse (AstNode root)
		{
			root.VisitChildren (this);
			return symbolTable;
		}

		public override void Accept (FunctionDeclaration declaration)
		{
			symbolTable.AddSymbol (declaration.Name);

			symbolTable.EnterScope ();

			foreach (string argument in declaration.Parameters) {
				symbolTable.AddSymbol (argument);
			}

			declaration.VisitChildren (this);

			symbolTable.ExitScope (declaration.Name);
		}

		public override void Accept (CodeBlock codeblock)
		{
			symbolTable.EnterScope ();
			codeblock.VisitChildren (this);
			symbolTable.ExitScope ();
		}

		public override void Accept (IfStatement ifStatement)
		{
			ifStatement.VisitChildren (this);
		}

		public override void Accept (AutoDeclaration autoDeclaration)
		{
			symbolTable.AddSymbol (autoDeclaration.Name);
			autoDeclaration.VisitChildren (this);
		}

		public override void Accept (VectorDeclaration vectorDeclaration)
		{
			symbolTable.AddSymbol (vectorDeclaration.Name);
		}

		public override void Accept (ArgumentList argumentList)
		{
			argumentList.VisitChildren (this);
		}

		public override void Accept (BinaryExpression binaryExpression)
		{
			binaryExpression.VisitChildren (this);
		}

		public override void Accept (IdentifierExpression identExpression)
		{
			if (!symbolTable.FindSymbol (identExpression.Name)) {
				context.ErrorLog.AddError (Errors.VariableAlreadyDefined, identExpression.Location, identExpression.Name);
			}
		}
	}
}

